; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s

; This test checks that commutative instructions where the operands are
; swapped are outlined as the same function.

; It also checks that non-commutative instructions outlined as different
; functions when the operands are swapped;

; These are identical functions, except that in the flipped functions,
; the operands in the adds are commuted.  However, since add instructions
; are commutative, we should still outline from all four as the same
; instruction.

define void @outline_from_add1() {
; CHECK-LABEL: @outline_from_add1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = add i32 %al, %bl
  %1 = add i32 %al, %cl
  %2 = add i32 %bl, %cl
  ret void
}

define void @outline_from_add2() {
; CHECK-LABEL: @outline_from_add2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = add i32 %al, %bl
  %1 = add i32 %al, %cl
  %2 = add i32 %bl, %cl
  ret void
}

define void @outline_from_flipped_add3() {
; CHECK-LABEL: @outline_from_flipped_add3(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = add i32 %bl, %al
  %1 = add i32 %cl, %al
  %2 = add i32 %cl, %bl
  ret void
}

define void @outline_from_flipped_add4() {
; CHECK-LABEL: @outline_from_flipped_add4(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = add i32 %bl, %al
  %1 = add i32 %cl, %al
  %2 = add i32 %cl, %bl
  ret void
}

; These are identical functions, except that in the flipped functions,
; the operands in the subtractions are commuted.  Since subtraction
; instructions are not commutative, we should outline the first two functions
; differently than the second two functions.

define void @outline_from_sub1() {
; CHECK-LABEL: @outline_from_sub1(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = sub i32 %al, %bl
  %1 = sub i32 %al, %cl
  %2 = sub i32 %bl, %cl
  ret void
}

define void @outline_from_sub2() {
; CHECK-LABEL: @outline_from_sub2(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_2(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = sub i32 %al, %bl
  %1 = sub i32 %al, %cl
  %2 = sub i32 %bl, %cl
  ret void
}

define void @dontoutline_from_flipped_sub3() {
; CHECK-LABEL: @dontoutline_from_flipped_sub3(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = sub i32 %bl, %al
  %1 = sub i32 %cl, %al
  %2 = sub i32 %cl, %bl
  ret void
}

define void @dontoutline_from_flipped_sub4() {
; CHECK-LABEL: @dontoutline_from_flipped_sub4(
; CHECK-NEXT:  entry:
; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
; CHECK-NEXT:    call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
; CHECK-NEXT:    ret void
;
entry:
  %a = alloca i32, align 4
  %b = alloca i32, align 4
  %c = alloca i32, align 4
  store i32 2, ptr %a, align 4
  store i32 3, ptr %b, align 4
  store i32 4, ptr %c, align 4
  %al = load i32, ptr %a
  %bl = load i32, ptr %b
  %cl = load i32, ptr %c
  %0 = sub i32 %bl, %al
  %1 = sub i32 %cl, %al
  %2 = sub i32 %cl, %bl
  ret void
}

; CHECK: define internal void @outlined_ir_func_0(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT:    store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT:    store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT:    store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT:    [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT:    [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT:    [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[AL]], [[BL]]
; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[AL]], [[CL]]
; CHECK-NEXT:    [[TMP2:%.*]] = add i32 [[BL]], [[CL]]

; CHECK: define internal void @outlined_ir_func_1(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT:    store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT:    store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT:    store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT:    [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT:    [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT:    [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK-NEXT:    [[TMP0:%.*]] = sub i32 [[BL]], [[AL]]
; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 [[CL]], [[AL]]
; CHECK-NEXT:    [[TMP2:%.*]] = sub i32 [[CL]], [[BL]]

; CHECK: define internal void @outlined_ir_func_2(ptr [[ARG0:%.*]], ptr [[ARG1:%.*]], ptr [[ARG2:%.*]]) #0 {
; CHECK: entry_to_outline:
; CHECK-NEXT:    store i32 2, ptr [[ARG0]], align 4
; CHECK-NEXT:    store i32 3, ptr [[ARG1]], align 4
; CHECK-NEXT:    store i32 4, ptr [[ARG2]], align 4
; CHECK-NEXT:    [[AL:%.*]] = load i32, ptr [[ARG0]], align 4
; CHECK-NEXT:    [[BL:%.*]] = load i32, ptr [[ARG1]], align 4
; CHECK-NEXT:    [[CL:%.*]] = load i32, ptr [[ARG2]], align 4
; CHECK-NEXT:    [[TMP0:%.*]] = sub i32 [[AL]], [[BL]]
; CHECK-NEXT:    [[TMP1:%.*]] = sub i32 [[AL]], [[CL]]
; CHECK-NEXT:    [[TMP2:%.*]] = sub i32 [[BL]], [[CL]]
